﻿// Enums.NET
// Copyright 2015 Tyler Brinkley. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;

namespace EnumsNET.NonGeneric
{
	/// <summary>
	/// A non-generic implementation of the static class <see cref="Enums"/>, similar to .NET's built-in <see cref="Enum"/> class.
	/// When the type is known at compile-time the <see cref="Enums"/> class should be used instead, to provide type safety and to avoid boxing.
	/// </summary>
	public static class NonGenericEnums
	{
		private static readonly ConcurrentDictionary<Type, IEnumsCache> _enumsCacheDictionary = new ConcurrentDictionary<Type, IEnumsCache>();

		internal static IEnumsCache GetEnumsCache(Type enumType)
		{
			Preconditions.NotNull(enumType, nameof(enumType));
			if (!enumType.IsEnum)
			{
				throw new ArgumentException("must be an enum type", nameof(enumType));
			}

			IEnumsCache enumsCache;
			if (!_enumsCacheDictionary.TryGetValue(enumType, out enumsCache))
			{
				enumsCache = (IEnumsCache)typeof(EnumsCache<>).MakeGenericType(enumType).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[0], null).Invoke(null);
				_enumsCacheDictionary.TryAdd(enumType, enumsCache);
			}
			return enumsCache;
		}

		#region "Properties"
		/// <summary>
		/// Indicates if <paramref name="enumType"/> is contiguous.
		/// </summary>
		/// <param name="enumType"></param>
		/// <returns>Indication if <paramref name="enumType"/> is contiguous.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsContiguous(Type enumType) => GetEnumsCache(enumType).IsContiguous;

		/// <summary>
		/// Retrieves the underlying type of <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <returns>The underlying type of <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static Type GetUnderlyingType(Type enumType) => GetEnumsCache(enumType).UnderlyingType;
		#endregion

		#region Type Methods
		/// <summary>
		/// Retrieves <paramref name="enumType"/>'s count of defined constants.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="uniqueValued"></param>
		/// <returns><paramref name="enumType"/>'s count of defined constants.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static int GetDefinedCount(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetDefinedCount(uniqueValued);

		/// <summary>
		/// Retrieves an array of <paramref name="enumType"/>'s defined constants' names in value order.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="uniqueValued"></param>
		/// <returns>Array of <paramref name="enumType"/>'s defined constants' names in value order.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static string[] GetNames(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetNames(uniqueValued);

		/// <summary>
		/// Retrieves an array of <paramref name="enumType"/> defined constants' values in value order.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="uniqueValued"></param>
		/// <returns>Array of <paramref name="enumType"/> defined constants' values in value order.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object[] GetValues(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetValues(uniqueValued);

		/// <summary>
		/// Retrieves an array of <paramref name="enumType"/> defined constants' descriptions in value order. Descriptions are taken from the <see cref="DescriptionAttribute"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="uniqueValued"></param>
		/// <returns>Array of <paramref name="enumType"/> defined constants' descriptions in value order.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static string[] GetDescriptions(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetDescriptions(uniqueValued);

		[Pure]
		public static string[] GetDescriptionsOrNames(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetDescriptionsOrNames(uniqueValued);

		public static string[] GetDescriptionsOrNames(Type enumType, Func<string, string> nameFormatter, bool uniqueValued = false) => GetEnumsCache(enumType).GetDescriptionsOrNames(nameFormatter, uniqueValued);

		[Pure]
		public static string[] GetEnumMemberValues(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetEnumMemberValues(uniqueValued);

		/// <summary>
		/// Retrieves an array of all of <paramref name="enumType"/>'s defined constants' attributes in value order.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="uniqueValued"></param>
		/// <returns>Array of all of <paramref name="enumType"/>'s defined constants' attributes in value order.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static Attribute[][] GetAllAttributes(Type enumType, bool uniqueValued = false) => GetEnumsCache(enumType).GetAllAttributes(uniqueValued);

		/// <summary>
		/// Returns -1 if <paramref name="x"/> is less than <paramref name="y"/> and returns 0 if <paramref name="x"/> equals <paramref name="y"/>
		/// and returns 1 if <paramref name="x"/> is greater than <paramref name="y"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/>, <paramref name="x"/>, or <paramref name="y"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="x"/> is not or cannot be converted to enum of <paramref name="enumType"/>
		/// -or-
		/// <paramref name="y"/> is not or cannot be converted to enum of <paramref name="enumType"/></exception>
		[Pure]
		public static int Compare(Type enumType, object x, object y) => GetEnumsCache(enumType).Compare(x, y);
		#endregion

		#region IsValid
		/// <summary>
		/// Indicates whether <paramref name="value"/> is defined or if <paramref name="enumType"/> is marked with <see cref="FlagsAttribute"/>
		/// whether it's a valid flag combination of <paramref name="enumType"/>'s defined values.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value">must be an enum value, <see cref="sbyte"/>, <see cref="byte"/>, <see cref="short"/>, <see cref="ushort"/>, <see cref="int"/>, <see cref="uint"/>, <see cref="long"/>, <see cref="ulong"/>, or <see cref="string"/></param>
		/// <returns>Indication whether the specified <paramref name="value"/> is defined or if <paramref name="enumType"/> is marked with <see cref="FlagsAttribute"/>
		/// whether it's a valid flag combination of <paramref name="enumType"/>'s defined values.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is not or cannot be converted to enum of <paramref name="enumType"/></exception>
		[Pure]
		public static bool IsValid(Type enumType, object value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, sbyte value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, byte value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, short value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, ushort value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, int value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, uint value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, long value) => GetEnumsCache(enumType).IsValid(value);

		/// <summary>
		/// Indicates if <paramref name="value"/> is valid for <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Indication if value is valid for <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsValid(Type enumType, ulong value) => GetEnumsCache(enumType).IsValid(value);
		#endregion

		#region IsDefined
		/// <summary>
		/// Indicates whether <paramref name="value"/> is defined in <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value">must be an enum value, <see cref="sbyte"/>, <see cref="byte"/>, <see cref="short"/>, <see cref="ushort"/>, <see cref="int"/>, <see cref="uint"/>, <see cref="long"/>, <see cref="ulong"/>, or <see cref="string"/></param>
		/// <returns>Indication whether <paramref name="value"/> is defined in <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is not or cannot be converted to enum of <paramref name="enumType"/></exception>
		[Pure]
		public static bool IsDefined(Type enumType, object value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Indicates whether a constant with the specified <paramref name="name"/> exists in <paramref name="enumType"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="name">The name to check existence.</param>
		/// <returns>Indication whether a constant with the specified <paramref name="name"/> exists in <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="name"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, string name) => GetEnumsCache(enumType).IsDefined(name);

		/// <summary>
		/// Indicates whether a constant with the specified <paramref name="name"/> exists in <paramref name="enumType"/>.
		/// <paramref name="ignoreCase"/> specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="name"></param>
		/// <param name="ignoreCase">Specifies whether the operation is case-insensitive.</param>
		/// <returns>Indication whether a constant with the specified <paramref name="name"/> exists in <paramref name="enumType"/>.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="name"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, string name, bool ignoreCase) => GetEnumsCache(enumType).IsDefined(name, ignoreCase);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, sbyte value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, byte value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, short value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, ushort value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, int value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, uint value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, long value) => GetEnumsCache(enumType).IsDefined(value);

		/// <summary>
		/// Returns an indication whether a constant with the specified <paramref name="value"/> exists in the enumeration.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsDefined(Type enumType, ulong value) => GetEnumsCache(enumType).IsDefined(value);
		#endregion

		#region IsWithinUnderlyingTypesValueRange
		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, sbyte value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, byte value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, short value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, ushort value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, int value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, uint value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, long value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);

		/// <summary>
		/// Returns an indication whether the specified <paramref name="value"/> is within the underlying types value range.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool IsWithinUnderlyingTypesValueRange(Type enumType, ulong value) => GetEnumsCache(enumType).IsWithinUnderlyingTypesValueRange(value);
		#endregion

		#region ToEnum
		/// <summary>
		/// Converts the specified <paramref name="value"/> to an enumeration member while checking that the result is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value">must be <see cref="sbyte"/>, <see cref="byte"/>, <see cref="short"/>, <see cref="ushort"/>, <see cref="int"/>, <see cref="uint"/>, <see cref="long"/>, <see cref="ulong"/>, or <see cref="string"/></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is not a valid type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, object value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 8-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, sbyte value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 8-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, byte value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 16-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, short value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 16-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, ushort value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 32-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, int value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 32-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, uint value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 64-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, long value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Converts the specified 64-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="validate"/> is true and <paramref name="value"/> is not a valid value</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the underlying type's value range</exception>
		[Pure]
		public static object ToEnum(Type enumType, ulong value, bool validate = true) => GetEnumsCache(enumType).ToEnum(value, validate);

		/// <summary>
		/// Tries to converts the specified <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value">must be <see cref="sbyte"/>, <see cref="byte"/>, <see cref="short"/>, <see cref="ushort"/>, <see cref="int"/>, <see cref="uint"/>, <see cref="long"/>, <see cref="ulong"/>, or <see cref="string"/></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, object value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 8-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, sbyte value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 8-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, byte value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 16-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, short value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 16-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, ushort value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 32-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, int value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 32-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, uint value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 64-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, long value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified 64-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. If it fails
		/// <paramref name="defaultEnum"/> is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ToEnumOrDefault(Type enumType, ulong value, object defaultEnum = null, bool validate = true) => GetEnumsCache(enumType).ToEnumOrDefault(value, defaultEnum, validate);

		/// <summary>
		/// Tries to converts the specified <paramref name="value"/> to an enumeration member while checking that the result is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value">must be <see cref="sbyte"/>, <see cref="byte"/>, <see cref="short"/>, <see cref="ushort"/>, <see cref="int"/>, <see cref="uint"/>, <see cref="long"/>, <see cref="ulong"/>, or <see cref="string"/></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, object value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 8-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, sbyte value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 8-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, byte value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 16-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, short value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 16-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, ushort value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 32-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, int value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 32-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, uint value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 64-bit signed integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, long value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);

		/// <summary>
		/// Tries to converts the specified 64-bit unsigned integer <paramref name="value"/> to an enumeration member while checking that the <paramref name="value"/> is within the
		/// underlying types value range. The optional parameter <paramref name="validate"/> indicates whether to check that the result is valid. An indication
		/// if the operation succeeded is returned and the result of the operation or if it fails the default enumeration value is stored in the output parameter <paramref name="result"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="validate"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryToEnum(Type enumType, ulong value, out object result, bool validate = true) => GetEnumsCache(enumType).TryToEnum(value, out result, validate);
		#endregion

		#region All Values Main Methods
		/// <summary>
		/// Validates that <paramref name="value"/> is valid. If it's not it throws an <see cref="ArgumentException"/> with the given <paramref name="paramName"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="paramName"></param>
		/// <returns><paramref name="value"/> for use in constructor initializers and fluent API's</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		[Pure]
		public static object Validate(Type enumType, object value, string paramName) => GetEnumsCache(enumType).Validate(value, paramName);

		/// <summary>
		/// Converts the specified <paramref name="value"/> to its equivalent string representation.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		[Pure]
		public static string AsString(Type enumType, object value) => GetEnumsCache(enumType).AsString(value);

		/// <summary>
		/// Converts the specified <paramref name="value"/> to its equivalent string representation according to the specified <paramref name="format"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="format"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="FormatException"><paramref name="format"/> is an invalid value</exception>
		[Pure]
		public static string AsString(Type enumType, object value, string format) => GetEnumsCache(enumType).AsString(value, format);

		[Pure]
		public static string AsString(Type enumType, object value, params EnumFormat[] formats) => GetEnumsCache(enumType).AsString(value, formats);

		[Pure]
		public static string AsString(Type enumType, string name) => GetEnumsCache(enumType).AsString(name);

		[Pure]
		public static string AsString(Type enumType, string name, string format) => GetEnumsCache(enumType).AsString(name, format);

		[Pure]
		public static string AsString(Type enumType, string name, params EnumFormat[] formats) => GetEnumsCache(enumType).AsString(name, formats);

		/// <summary>
		/// Converts the specified <paramref name="value"/> to its equivalent string representation according to the specified <paramref name="format"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="format"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/>, <paramref name="value"/>, or <paramref name="format"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="FormatException"><paramref name="format"/> is an invalid value.</exception>
		[Pure]
		public static string Format(Type enumType, object value, string format) => GetEnumsCache(enumType).Format(value, format);

		[Pure]
		public static string Format(Type enumType, object value, params EnumFormat[] formats) => GetEnumsCache(enumType).Format(value, formats);

		[Pure]
		public static string Format(Type enumType, string name, string format) => GetEnumsCache(enumType).Format(name, format);

		[Pure]
		public static string Format(Type enumType, string name, params EnumFormat[] formats) => GetEnumsCache(enumType).Format(name, formats);

		/// <summary>
		/// Returns an object with the enum's underlying value.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		[Pure]
		public static object GetUnderlyingValue(Type enumType, object value) => GetEnumsCache(enumType).GetUnderlyingValue(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to an <see cref="sbyte"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="sbyte"/>'s value range without overflowing</exception>
		[Pure]
		public static sbyte ToSByte(Type enumType, object value) => GetEnumsCache(enumType).ToSByte(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to a <see cref="byte"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="byte"/>'s value range without overflowing</exception>
		[Pure]
		public static byte ToByte(Type enumType, object value) => GetEnumsCache(enumType).ToByte(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to an <see cref="short"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="short"/>'s value range without overflowing</exception>
		[Pure]
		public static short ToInt16(Type enumType, object value) => GetEnumsCache(enumType).ToInt16(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to a <see cref="ushort"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="ushort"/>'s value range without overflowing</exception>
		[Pure]
		public static ushort ToUInt16(Type enumType, object value) => GetEnumsCache(enumType).ToUInt16(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to an <see cref="int"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="int"/>'s value range without overflowing</exception>
		[Pure]
		public static int ToInt32(Type enumType, object value) => GetEnumsCache(enumType).ToInt32(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to a <see cref="uint"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="uint"/>'s value range without overflowing</exception>
		[Pure]
		public static uint ToUInt32(Type enumType, object value) => GetEnumsCache(enumType).ToUInt32(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to an <see cref="long"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="long"/>'s value range without overflowing</exception>
		[Pure]
		public static long ToInt64(Type enumType, object value) => GetEnumsCache(enumType).ToInt64(value);

		/// <summary>
		/// Tries to convert <paramref name="value"/> to a <see cref="ulong"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> cannot fit within <see cref="ulong"/>'s value range without overflowing</exception>
		[Pure]
		public static ulong ToUInt64(Type enumType, object value) => GetEnumsCache(enumType).ToUInt64(value);
		#endregion

		#region Defined Values Main Methods
		/// <summary>
		/// Retrieves the name of the constant in <paramref name="enumType"/> that has the specified <paramref name="value"/>. If <paramref name="value"/>
		/// is not defined null is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Name of the constant in <paramref name="enumType"/> that has the specified <paramref name="value"/>. If <paramref name="value"/>
		/// is not defined null is returned.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		[Pure]
		public static string GetName(Type enumType, object value) => GetEnumsCache(enumType).GetName(value);

		/// <summary>
		/// Retrieves the description of the constant in the enumeration that has the specified <paramref name="value"/>. If <paramref name="value"/>
		/// is not defined or no associated <see cref="DescriptionAttribute"/> is found then null is returned.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns>Description of the constant in the enumeration that has the specified <paramref name="value"/>. If <paramref name="value"/>
		/// is not defined or no associated <see cref="DescriptionAttribute"/> is found then null is returned.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		[Pure]
		public static string GetDescription(Type enumType, object value) => GetEnumsCache(enumType).GetDescription(value);

		/// <summary>
		/// Retrieves the description of the constant in the enumeration that has the specified <paramref name="name"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="name"></param>
		/// <returns>Description from <see cref="DescriptionAttribute"/> if defined, else null</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="name"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static string GetDescription(Type enumType, string name) => GetEnumsCache(enumType).GetDescription(name);

		[Pure]
		public static string GetDescriptionOrName(Type enumType, object value) => GetEnumsCache(enumType).GetDescriptionOrName(value);

		public static string GetDescriptionOrName(Type enumType, object value, Func<string, string> nameFormatter) => GetEnumsCache(enumType).GetDescriptionOrName(value, nameFormatter);

		[Pure]
		public static string GetDescriptionOrName(Type enumType, string name) => GetEnumsCache(enumType).GetDescriptionOrName(name);

		public static string GetDescriptionOrName(Type enumType, string name, Func<string, string> nameFormatter) => GetEnumsCache(enumType).GetDescriptionOrName(name, nameFormatter);

		[Pure]
		public static string GetEnumMemberValue(Type enumType, object value) => GetEnumsCache(enumType).GetEnumMemberValue(value);

		[Pure]
		public static string GetEnumMemberValue(Type enumType, string name) => GetEnumsCache(enumType).GetEnumMemberValue(name);
		#endregion

		#region Attributes
		/// <summary>
		/// Retrieves an array of all the <see cref="Attribute"/>'s of the constant in the enumeration that has the specified <paramref name="value"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns><see cref="Attribute"/> array if value is defined, else null</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is invalid</exception>
		[Pure]
		public static Attribute[] GetAllAttributes(Type enumType, object value) => GetEnumsCache(enumType).GetAllAttributes(value);

		/// <summary>
		/// Retrieves an array of all the <see cref="Attribute"/>'s of the constant in the enumeration that has the specified <paramref name="name"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="name"></param>
		/// <returns><see cref="Attribute"/> array if name is defined, else null</returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="name"/> is null</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static Attribute[] GetAllAttributes(Type enumType, string name) => GetEnumsCache(enumType).GetAllAttributes(name);
		#endregion

		#region Parsing
		/// <summary>
		/// Converts the string representation of the name or numeric value of one or more enumerated constants
		/// to an equivalent enumerated object.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is either an empty string or only contains white space.
		/// -or-
		/// <paramref name="value"/> is a name, but not one of the named constants defined for the enumeration.</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of the underlying type of <paramref name="enumType"/></exception>
		[Pure]
		public static object Parse(Type enumType, string value) => GetEnumsCache(enumType).Parse(value);

		/// <summary>
		/// Converts the string representation of the name or numeric value of one or more enumerated constants
		/// to an equivalent enumerated object. A parameter specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="ignoreCase"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is either an empty string or only contains white space.
		/// -or-
		/// <paramref name="value"/> is a name, but not one of the named constants defined for the enumeration.</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of the underlying type of <paramref name="enumType"/></exception>
		[Pure]
		public static object Parse(Type enumType, string value, bool ignoreCase) => GetEnumsCache(enumType).Parse(value, ignoreCase);

		/// <summary>
		/// Converts the string representation of an enumerated constant using the given <paramref name="parseFormatOrder"/>.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="parseFormatOrder"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is either an empty string or only contains white space.
		/// -or-
		/// <paramref name="value"/> is a name, but not one of the named constants defined for the enumeration.</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of the underlying type of <paramref name="enumType"/></exception>
		[Pure]
		public static object Parse(Type enumType, string value, params EnumFormat[] parseFormatOrder) => GetEnumsCache(enumType).Parse(value, parseFormatOrder);

		/// <summary>
		/// Converts the string representation of an enumerated constant using the given <paramref name="parseFormatOrder"/>.
		/// A parameter specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="ignoreCase"></param>
		/// <param name="parseFormatOrder"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> or <paramref name="value"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type
		/// -or-
		/// <paramref name="value"/> is either an empty string or only contains white space.
		/// -or-
		/// <paramref name="value"/> is a name, but not one of the named constants defined for the enumeration.</exception>
		/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of the underlying type of <paramref name="enumType"/></exception>
		[Pure]
		public static object Parse(Type enumType, string value, bool ignoreCase, params EnumFormat[] parseFormatOrder) => GetEnumsCache(enumType).Parse(value, ignoreCase, parseFormatOrder);

		/// <summary>
		/// Tries to convert the string representation of the name or numeric value of one or more enumerated
		/// constants to an equivalent enumerated object but if it fails returns the specified default enumerated value.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ParseOrDefault(Type enumType, string value, object defaultEnum = null) => GetEnumsCache(enumType).ParseOrDefault(value, defaultEnum);

		/// <summary>
		/// Tries to convert the string representation of the name or numeric value of one or more enumerated
		/// constants to an equivalent enumerated object but if it fails returns the specified default enumerated value.
		/// A parameter specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="ignoreCase"></param>
		/// <param name="defaultEnum"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ParseOrDefault(Type enumType, string value, bool ignoreCase, object defaultEnum = null) => GetEnumsCache(enumType).ParseOrDefault(value, ignoreCase, defaultEnum);

		/// <summary>
		/// Tries to convert the string representation of an enumerated constant using the given <paramref name="parseFormatOrder"/>
		/// but if it fails returns the specified default enumerated value.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="parseFormatOrder"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ParseOrDefault(Type enumType, string value, object defaultEnum, params EnumFormat[] parseFormatOrder) => GetEnumsCache(enumType).ParseOrDefault(value, defaultEnum, parseFormatOrder);

		/// <summary>
		/// Tries to convert the string representation of an enumerated constant using the given <paramref name="parseFormatOrder"/>
		/// but if it fails returns the specified default enumerated value. A parameter specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="ignoreCase"></param>
		/// <param name="defaultEnum"></param>
		/// <param name="parseFormatOrder"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static object ParseOrDefault(Type enumType, string value, bool ignoreCase, object defaultEnum, params EnumFormat[] parseFormatOrder) => GetEnumsCache(enumType).ParseOrDefault(value, ignoreCase, defaultEnum, parseFormatOrder);

		/// <summary>
		/// Tries to convert the string representation of the name or numeric value of one or more enumerated
		/// constants to an equivalent enumerated object. The return value indicates whether the conversion succeeded.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryParse(Type enumType, string value, out object result) => GetEnumsCache(enumType).TryParse(value, out result);

		/// <summary>
		/// Tries to convert the string representation of the name or numeric value of one or more enumerated
		/// constants to an equivalent enumerated object. The return value indicates whether the conversion succeeded.
		/// A parameter specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="ignoreCase"></param>
		/// <param name="result"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryParse(Type enumType, string value, bool ignoreCase, out object result) => GetEnumsCache(enumType).TryParse(value, ignoreCase, out result);

		/// <summary>
		/// Tries to convert the string representation of an enumerated constant using the given <paramref name="parseFormatOrder"/>.
		/// The return value indicates whether the conversion succeeded.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="result"></param>
		/// <param name="parseFormatOrder"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryParse(Type enumType, string value, out object result, params EnumFormat[] parseFormatOrder) => GetEnumsCache(enumType).TryParse(value, out result, parseFormatOrder);

		/// <summary>
		/// Tries to convert the string representation of an enumerated constant using the given <paramref name="parseFormatOrder"/>.
		/// The return value indicates whether the conversion succeeded. A parameter specifies whether the operation is case-insensitive.
		/// </summary>
		/// <param name="enumType"></param>
		/// <param name="value"></param>
		/// <param name="ignoreCase"></param>
		/// <param name="result"></param>
		/// <param name="parseFormatOrder"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"><paramref name="enumType"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="enumType"/> is not an enum type</exception>
		[Pure]
		public static bool TryParse(Type enumType, string value, bool ignoreCase, out object result, params EnumFormat[] parseFormatOrder) => GetEnumsCache(enumType).TryParse(value, ignoreCase, out result, parseFormatOrder);
		#endregion
	}
}
